package com.hhkj.admin.bank.domain;

import com.baomidou.mybatisplus.annotation.FieldStrategy;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableName;
import com.fasterxml.jackson.annotation.JsonFormat;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.hhkj.admin.bank.common.cont.RuleConst;
import com.hhkj.admin.bank.common.mybatis.handler.QuestionOrderRuleHandler;
import com.hhkj.admin.bank.common.mybatis.handler.TestCorrectConfMapHandler;
import com.hhkj.admin.bank.model.extend.QuestionCorrectRule;
import com.hhkj.admin.bank.model.extend.QuestionOrderRule;
import com.hhkj.admin.course.common.mybatis.handler.StrIntMapHandler;
import com.hhkj.admin.question.common.cont.QuestionTypeEnum;
import com.ruoyi.common.annotation.Excel;
import com.ruoyi.common.core.domain.BizBaseEntity;
import com.ruoyi.common.mybatis.handler.StringListHandler;
import com.ruoyi.common.valid.VAdd;
import com.ruoyi.common.valid.VEdit;
import com.ruoyi.common.valid.emun.EnumValueCheck;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.NoArgsConstructor;
import lombok.experimental.Accessors;

import javax.validation.Valid;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotNull;
import java.math.BigDecimal;
import java.util.*;

/**
 * 题库抽题规则对象 t_bank_rule
 *
 * @author ruoyi
 * @since 2023-05-11
 */
@Data
@EqualsAndHashCode(callSuper = true)
@Accessors(chain = true)
@TableName(value = "t_bank_rule", autoResultMap = true)
@NoArgsConstructor
@AllArgsConstructor
public class BankRule extends BizBaseEntity
{
    private static final long serialVersionUID = 1L;

    /** 类型 group 规则集、single 单个规则 */
    @Excel(name = "类型 规则集:group、单个规则:single")
    private String typeCode;

    /** 课程id 关联 t_course 表的 id 字段 */
    @Excel(name = "课程id 关联 t_course 表的 id 字段")
    @TableField(updateStrategy = FieldStrategy.NEVER)
    private Long courseId;

    /** 课程名称 */
    @TableField(exist = false)
    private String courseName;

    /** 上级课程id */
    @NotNull(message = "类别信息不能为空", groups = {VAdd.class})
    private Long courseParentId;

    /** 上级课程名称 */
    @TableField(exist = false)
    private String courseParentName;

    /** 类目id */
    @TableField(exist = false)
    private Long courseRootId;

    /** 类目名称 */
    @TableField(exist = false)
    private String courseRootName;

    /** 课程题库类型id 关联 t_course_bank_type 表的 id 字段 */
    @Excel(name = "课程题库类型id 关联 t_course_bank_type 表的 id 字段")
    @NotNull(message = "课程信息不能为空", groups = {VAdd.class})
    @TableField(updateStrategy = FieldStrategy.NEVER)
    private Long courseBankTypeId;

    /** 课程题库类型名称 */
    @TableField(exist = false)
    private String courseBankTypeName;

    /** 上级规则id 关联 t_bank_rule 表的 id 字段 */
    @Excel(name = "上级规则id 关联 t_bank_rule 表的 id 字段")
    private Long parentId;

    /** 练习题库规则指定类别：unify 统一、difference 区分 */
    @Excel(name = "练习题库规则指定类别：统一:unify、区分:difference")
    @NotBlank(message = "练习题库规则指定类别不能为空", groups = {VAdd.class, VEdit.class})
    @EnumValueCheck(message = "练习题库规则指定类别错误: unify 统一、difference 区分", groups = {VAdd.class, VEdit.class}, target = RuleConst.ConfModeType.class)
    private String practiceConfModeTypeCode;

    /** 练习站总题库百分比 */
    @Excel(name = "练习占总题库百分比")
    @NotNull(message = "练习占总题库百分比", groups = {VAdd.class, VEdit.class})
    // @DecimalMax(message = "练习占总题库百分比范围为0~100", value = "100", groups = {VAdd.class, VEdit.class})
    // @DecimalMin(message = "练习占总题库百分比范围为0~100", value = "0", groups = {VAdd.class, VEdit.class})
    private BigDecimal practicePercent;

    /** 练习模式 json 数据 答题模式:answer、背题模式:recitation ["answer","recitation"] */
    @Excel(name = "练习模式 json 数据 答题模式:answer、背题模式:recitation")
    @TableField(typeHandler = StringListHandler.class)
    // @NotEmpty(message = "练习模式不能为空", groups = {VAdd.class, VEdit.class})
    // @EnumListCheck(message = "测试题库规则指定类别错误: 答题模式:answer、背题模式:recitation", groups = {VAdd.class, VEdit.class}, target = RuleConst.PracticeMode.class)
    private List<String> practiceModeCodeList = Arrays.asList("answer", "recitation");

    /** 练习题库排序规则 */
    @Valid
    // @NotNull(message = "练习模式排序规则不能为空", groups = {VAdd.class, VEdit.class})
    @TableField(typeHandler = QuestionOrderRuleHandler.class)
    private QuestionOrderRule practiceOrderRule;

    /** 测试题库规则指定类别：unify 统一、difference 区分 */
    @Excel(name = "测试题库规则指定类别：统一:unify、区分:difference")
    @NotBlank(message = "测试题库规则指定类别不能为空", groups = {VAdd.class, VEdit.class})
    @EnumValueCheck(message = "测试题库规则指定类别错误: unify 统一、difference 区分", groups = {VAdd.class, VEdit.class}, target = RuleConst.ConfModeType.class)
    private String testConfModeTypeCode;

    /** 测试题库中占练习题库百分比 */
    @Excel(name = "测试题库中占练习题库百分比")
    private BigDecimal testPracticePercent;

    /** 测试题库中占剩余题库百分比 */
    @Excel(name = "测试题库中占剩余题库百分比")
    private BigDecimal testResiduePercent;

    /** 测试时长分钟 */
    @Excel(name = "测试时长分钟")
    private Integer testDurationMinute;

    /** 测试题目数量配置'{"single":12,"judge":12,"case":4}' */
    @Excel(name = "测试题目数量配置")
    @TableField(typeHandler = StrIntMapHandler.class)
    private Map<String, Integer> testAmountConfMap;

    /** 测试题目分数配置'{"single":{"mark":12},"multiple":{"mark":12,"incompleteHalfMarkFlag":true}}' */
    @Excel(name = "测试题目分数配置")
    @TableField(typeHandler = TestCorrectConfMapHandler.class)
    private Map<String, QuestionCorrectRule> testCorrectConfMap;

    /** 测试题库排序规则 */
    @TableField(typeHandler = QuestionOrderRuleHandler.class)
    private QuestionOrderRule testOrderRule;

    /** 测试及格分数 */
    private BigDecimal testPassMark;

    /** 是否打乱选项顺序 1-是 0-否 */
    private Integer testShuffleOptionFlag;

    /** 上级id列表 */
    @JsonIgnore
    @TableField(exist = false)
    private List<Long> parentIdList;

    /** 是否有科目未配置 */
    @TableField(exist = false)
    private boolean existUnConfigCourse;

    @Override
    @NotNull(message = "唯一主键不能为空", groups = {VEdit.class})
    public Long getId()
    {
        return super.getId();
    }

    public String getTypeCode()
    {
        return (typeCode == null || RuleConst.Type.GROUP.getCode().equals(typeCode)) ?
                RuleConst.Type.GROUP.getCode() : RuleConst.Type.SINGLE.getCode();
    }

    public Long getParentId()
    {
        return this.parentId;
    }

    @JsonIgnore(value = false)
    @JsonFormat(pattern = "yyyy-MM-dd")
    public Date getCreateTime()
    {
        return super.getCreateTime();
    }

    public BankRule(Long courseId, String courseName)
    {
        this.courseId = courseId;
        this.courseName = courseName;
    }

    /**
     * 匹配题目列表信息是否满足信息
     *
     * @param bankPo 题库信息
     */
    public List<String> matchBankErrorInfo(Bank bankPo)
    {
        Map<String, Integer> bankTypeAmountConf = bankPo.getTypeAmountConf();
        List<String> resultList = new ArrayList<>();
        for (Map.Entry<String, Integer> testAmountConfMapEntry : this.testAmountConfMap.entrySet()) {
            if ((!bankTypeAmountConf.containsKey(testAmountConfMapEntry.getKey()) && testAmountConfMapEntry.getValue() > 0) ||
                    (bankTypeAmountConf.containsKey(testAmountConfMapEntry.getKey())
                            && bankTypeAmountConf.get(testAmountConfMapEntry.getKey()) < testAmountConfMapEntry.getValue()
                    )) {
                resultList.add(QuestionTypeEnum.getNameByCode(testAmountConfMapEntry.getKey()) + "测试题库数量不满足选题规则");
            }
        }
        return resultList;
    }

    /**
     * 复制练习相关信息字段值
     *
     * @param source 信息来源
     */
    public void copyPractiseProperties(BankRule source)
    {
        this.setPracticePercent(source.getPracticePercent());
        this.setPracticeModeCodeList(source.getPracticeModeCodeList());
        this.setPracticeOrderRule(source.getPracticeOrderRule());
    }

    /**
     * 复制练习相关信息字段值
     *
     * @param source 信息来源
     */
    public void copyTestProperties(BankRule source)
    {
        this.setTestPracticePercent(source.getTestPracticePercent());
        this.setTestResiduePercent(source.getTestResiduePercent());
        this.setTestDurationMinute(source.getTestDurationMinute());
        this.setTestAmountConfMap(source.getTestAmountConfMap());
        this.setTestCorrectConfMap(source.getTestCorrectConfMap());
        this.setTestOrderRule(source.getTestOrderRule());
    }

    public boolean hasCourseChildrenRule()
    {
        return (RuleConst.ConfModeType.DIFFERENCE.getCode().equals(this.getTestConfModeTypeCode())
                || RuleConst.ConfModeType.DIFFERENCE.getCode().equals(this.getPracticeConfModeTypeCode()));
    }

}
